use std::collections::vec_deque::Iter;
use std::collections::VecDeque;

use bytes::{BufMut, Bytes};

use crate::utils::slice::{crc32_ngx_var_hash, slice_ngx_var_eq};

const HEADERS_INIT_CAPACITY: usize = 128;
const HEADERS_HASH_SLOTS: usize = 32;

#[allow(dead_code)]
pub struct HttpHeader {
    name: Bytes,
    value: Bytes,
    hash_key: u32,
    del: bool,
}

#[allow(dead_code)]
impl HttpHeader {
    #[inline]
    pub fn new(name: Bytes) -> Self {
        let hash_key = crc32_ngx_var_hash(&name);

        HttpHeader {
            name,
            value: Bytes::new(),
            hash_key,
            del: false,
        }
    }

    #[inline]
    pub fn with_kv(name: Bytes, value: Bytes) -> Self {
        let hash_key = crc32_ngx_var_hash(&name);
        HttpHeader {
            name,
            value,
            hash_key,
            del: false,
        }
    }

    #[inline]
    pub fn get_name(&self) -> &[u8] {
        &self.name
    }

    #[inline]
    pub fn clone_name(&self) -> Bytes {
        self.name.clone()
    }

    #[inline]
    pub fn get_value(&self) -> &[u8] {
        &self.value
    }

    #[inline]
    pub fn clone_value(&self) -> Bytes {
        self.value.clone()
    }

    #[inline]
    pub fn set_value(&mut self, value: Bytes) {
        self.value = value;
    }

    #[inline]
    pub fn value_contain(&self, target: &[u8]) -> bool {
        let iter = self.value.split(|c| *c == b',');
        for mut v in iter {
            v = v.trim_ascii();
            if v.eq_ignore_ascii_case(target) {
                return true;
            }
        }

        false
    }

    #[inline]
    pub fn get_hash_key(&self) -> u32 {
        self.hash_key
    }
}

// 该headers中的header只做标记删除.
pub struct HttpHeaders {
    list: VecDeque<HttpHeader>,
    // 使用HEADERS_HASH_SLOTS组成的hash table
    // (u32 is hash_key, usize is list index)
    hash_tab: [Vec<(u32, usize)>; HEADERS_HASH_SLOTS],
    elements: usize,
}

impl std::fmt::Debug for HttpHeaders {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut ds = f.debug_struct("HttpHeaders");
        for v in self.list.iter() {
            if v.del {
                continue;
            }
            ds.field(&String::from_utf8_lossy(&v.name), &v.value);
        }
        ds.finish()
    }
}

#[allow(dead_code)]
impl HttpHeaders {
    pub fn new() -> Self {
        HttpHeaders {
            list: VecDeque::with_capacity(HEADERS_INIT_CAPACITY),
            hash_tab: [const { Vec::new() }; HEADERS_HASH_SLOTS],
            elements: 0,
        }
    }

    pub fn append_header(&mut self, header: HttpHeader) {
        let list_index = self.list.len();
        let hash_key = header.hash_key;
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        self.list.push_back(header);
        self.hash_tab[hash_slot].push((hash_key, list_index));
        self.elements += 1;
    }

    // 向尾部追加header, 不对同名header进行覆盖.
    pub fn append_header_with_kv(&mut self, name: Bytes, value: Bytes) {
        let header = HttpHeader::with_kv(name, value);
        self.append_header(header);
    }

    // 如果存在同名header, 将首个找到的同名header的value设置为传入的value, 并将其他的同名header标记删除.
    // 如果不存在同名的header, 追加一个新的header.
    pub fn set_header(&mut self, name: Bytes, value: Bytes) {
        let hash_key = crc32_ngx_var_hash(&name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        let mut set = false;

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];
            if v.0 == hash_key
                && header.name.eq_ignore_ascii_case(&name)
                && !header.del
            {
                if !set {
                    self.list[v.1].value = value.clone();
                    set = true;
                    continue;
                }

                self.list[v.1].del = true;
                self.elements -= 1;
            }
        }

        if set {
            return;
        }

        let header = HttpHeader::with_kv(name, value);
        let list_index = self.list.len();

        self.list.push_back(header);
        self.hash_tab[hash_slot].push((hash_key, list_index));
        self.elements += 1;
    }

    // headers中允许存在多个相同lower_name的header.
    // index表示获取第几个相同lower_name的header.
    pub fn get_header(&self, name: &[u8]) -> Option<&HttpHeader> {
        let hash_key = crc32_ngx_var_hash(name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];
            if v.0 == hash_key
                && header.name.eq_ignore_ascii_case(name)
                && !header.del
            {
                return Some(header);
            }
        }

        None
    }

    pub fn get_header_all(&self, name: &[u8]) -> Vec<&HttpHeader> {
        let hash_key = crc32_ngx_var_hash(name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        let mut res = Vec::with_capacity(4);

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];
            if v.0 == hash_key
                && header.name.eq_ignore_ascii_case(name)
                && !header.del
            {
                res.push(header);
            }
        }

        res
    }

    // 等价于ngx_var的方式获取, 将忽略大小写的基础上将'-'当做'_'进行查找
    pub fn ngx_var_get_header(&self, name: &[u8]) -> Option<&HttpHeader> {
        let hash_key = crc32_ngx_var_hash(name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];

            if v.0 == hash_key
                && slice_ngx_var_eq(&header.name, name)
                && !header.del
            {
                return Some(header);
            }
        }

        None
    }

    // 等价ngx_var的方式获取, 将忽略大小写的基础上将'-'当做'_'进行查找
    pub fn ngx_var_get_header_all(&self, name: &[u8]) -> Vec<&HttpHeader> {
        let hash_key = crc32_ngx_var_hash(name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        let mut res = Vec::with_capacity(4);

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];

            if v.0 == hash_key
                && slice_ngx_var_eq(&header.name, name)
                && !header.del
            {
                res.push(header);
            }
        }

        res
    }

    // 删除首个同名的header.
    // 因headers是标记删除, 此处删除首个未被标记为del的同名header
    pub fn del_header_once(&mut self, name: &[u8]) -> bool {
        let hash_key = crc32_ngx_var_hash(name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];
            if v.0 == hash_key
                && header.name.eq_ignore_ascii_case(name)
                && !header.del
            {
                self.list[v.1].del = true;
                self.elements -= 1;
                return true;
            }
        }

        false
    }

    // 删除全部的的同名header.
    pub fn del_header_all(&mut self, name: &[u8]) {
        let hash_key = crc32_ngx_var_hash(name);
        let hash_slot = hash_key as usize % HEADERS_HASH_SLOTS;

        for v in &self.hash_tab[hash_slot] {
            let header = &self.list[v.1];

            if v.0 == hash_key
                && header.name.eq_ignore_ascii_case(name)
                && !header.del
            {
                self.list[v.1].del = true;
                self.elements -= 1;
            }
        }
    }

    pub fn clone(&self) -> HttpHeaders {
        let mut headers = HttpHeaders::new();
        for h in &self.list {
            if h.del {
                continue;
            }

            headers.append_header_with_kv(h.clone_name(), h.clone_value());
        }

        headers
    }

    // 将self中的header转移至dst, 并清空self的headers.
    pub fn move_headers(&mut self, dst: &mut HttpHeaders) {
        while let Some(h) = self.list.pop_front() {
            if h.del {
                continue;
            }

            dst.set_header(h.name, h.value);
        }

        self.list.clear();
        for v in self.hash_tab.iter_mut() {
            v.clear();
        }
    }

    pub fn len(&self) -> usize {
        self.elements
    }

    pub fn iter(&self) -> HttpHeadersIter<'_> {
        HttpHeadersIter {
            base_iter: self.list.iter(),
        }
    }

    // 不包含empty line.
    pub fn write_byes_size(&self) -> usize {
        let mut size: usize = 0;

        for v in &self.list {
            if v.del {
                continue;
            }

            size += v.name.len();
            size += 2; // ": "
            size += v.value.len();
            size += 2; // '\r\n'
        }

        size
    }

    // 将headers序列化到buf
    pub fn write_buf<B>(&self, buf: &mut B) -> usize
    where
        B: BufMut + ?Sized,
    {
        let mut size: usize = 0;
        for v in &self.list {
            if v.del {
                continue;
            }

            buf.put_slice(&v.name);
            buf.put_slice(": ".as_bytes());
            buf.put_slice(&v.value);
            buf.put_slice("\r\n".as_bytes());

            size += v.name.len();
            size += 2; // ": "
            size += v.value.len();
            size += 2; // "\r\n"
        }

        size
    }
}

pub struct HttpHeadersIter<'a> {
    base_iter: Iter<'a, HttpHeader>,
}

impl<'a> Iterator for HttpHeadersIter<'a> {
    type Item = &'a HttpHeader;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let header = match self.base_iter.next() {
                Some(h) => h,
                None => {
                    return None;
                }
            };

            if header.del {
                continue;
            }

            return Some(header);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_http_headers() {
        let mut headers = HttpHeaders::new();

        headers.append_header_with_kv("host".into(), Bytes::from("www.a.com"));
        headers.append_header_with_kv("test".into(), "123".into());
        headers.append_header_with_kv("test".into(), "456".into());
        headers.append_header_with_kv("AAA".into(), "aaa".into());
        assert!(headers.len() == 4);

        let mut buf: Vec<u8> = Vec::with_capacity(headers.write_byes_size());
        let res = headers.write_buf(&mut buf);

        assert_eq!(res, 49);
        let header_str1 =
            "host: www.a.com\r\ntest: 123\r\ntest: 456\r\nAAA: aaa\r\n";
        assert_eq!(&buf, header_str1.as_bytes());

        headers.set_header("test".into(), "bbbb".into());
        assert!(headers.len() == 3);

        let mut buf: Vec<u8> = Vec::with_capacity(headers.write_byes_size());
        let res = headers.write_buf(&mut buf);
        assert_eq!(res, 39);
        let header_str2 = "host: www.a.com\r\ntest: bbbb\r\nAAA: aaa\r\n";
        assert_eq!(&buf, header_str2.as_bytes());

        headers.append_header_with_kv("test".into(), "ccc".into());
        assert!(headers.len() == 4);
        let mut buf: Vec<u8> = Vec::with_capacity(headers.write_byes_size());
        let res = headers.write_buf(&mut buf);
        assert_eq!(res, 50);
        let header_str3 =
            "host: www.a.com\r\ntest: bbbb\r\nAAA: aaa\r\ntest: ccc\r\n";
        assert_eq!(&buf, header_str3.as_bytes());

        headers.del_header_once("aaa".as_bytes());
        assert!(headers.len() == 3);
        let mut buf: Vec<u8> = Vec::with_capacity(headers.write_byes_size());
        let res = headers.write_buf(&mut buf);
        assert_eq!(res, 40);
        let header_str4 = "host: www.a.com\r\ntest: bbbb\r\ntest: ccc\r\n";
        assert_eq!(&buf, header_str4.as_bytes());

        headers.del_header_all("test".as_bytes());
        assert!(headers.len() == 1);
        let mut buf: Vec<u8> = Vec::with_capacity(headers.write_byes_size());
        let res = headers.write_buf(&mut buf);
        assert_eq!(res, 17);
        let header_str5 = "host: www.a.com\r\n";
        assert_eq!(&buf, header_str5.as_bytes());

        headers.set_header("abc".into(), "abc".into());
        headers.set_header("def".into(), "def".into());
        assert!(headers.len() == 3);

        headers.del_header_all("ggg".as_bytes());
        assert!(headers.len() == 3);

        let mut iter = headers.iter();

        let h1 = iter.next().unwrap();
        assert_eq!(h1.get_name(), b"host");
        assert_eq!(h1.get_value(), b"www.a.com");
        let h2 = iter.next().unwrap();
        assert_eq!(h2.get_name(), b"abc");
        assert_eq!(h2.get_value(), b"abc");
        let h3 = iter.next().unwrap();
        assert_eq!(h3.get_name(), b"def");
        assert_eq!(h3.get_value(), b"def");

        assert!(iter.next().is_none());

        let host_header_v = headers.get_header_all(b"Host");
        assert_eq!(host_header_v.len(), 1);
        assert_eq!(host_header_v[0].get_name(), b"host");
        assert_eq!(host_header_v[0].get_value(), b"www.a.com");

        let abc_header = headers.get_header(b"ABC").unwrap();
        assert_eq!(abc_header.get_name(), b"abc");
        assert_eq!(abc_header.get_value(), b"abc");
    }
}
